﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Soft
{
    /// <summary>
    /// 拓展方法
    /// </summary>
    public static class ObjectExtensions
    {

        /// <summary>
        /// ASCII 
        /// </summary>
        public static object ASCII { get; private set; }


        /// <summary>
        /// 判断是否是周末
        /// </summary>
        /// <param name="day"></param>
        /// <returns></returns>
        public static bool IsWeekend(this DateTime day)
        {
            return day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday;
        }


        /// <summary>
        /// dateTime格式化为 yyyy-MM-dd
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public static string ToDateString(this DateTime d)
        {
            return d.ToString("yyyy-MM-dd");
        }


        /// <summary>
        /// dateTime 格式化为时间格式  hh:mm:ss
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public static string ToTimeString(this DateTime d)
        {
            return d.ToString("HH:mm:ss");
        }


        /// <summary>
        /// 时间格式yyyy-MM-dd HH:mm:ss.fff
        /// </summary>
        /// <param name="d"></param>
        /// <param name="millisecond"></param>
        /// <returns></returns>
        public static string ToDateTimeString(this DateTime d, bool millisecond = false)
        {
            if (millisecond)
            {
                return d.ToString("yyyy-MM-dd HH:mm:ss.fff");
            }
            return d.ToString("yyyy-MM-dd HH:mm:ss");
        }


        /// <summary>
        /// 根据时间格式 格式化时间
        /// </summary>
        /// <param name="d"></param>
        /// <param name="timeUnit"></param>
        /// <param name="cn"></param>
        /// <returns></returns>
        public static string ToDateTimeString(this DateTime d, TimeUnit timeUnit, bool cn = true)
        {
            string result;
            switch (timeUnit)
            {
                case TimeUnit.Minute:
                    result = (cn ? d.ToString("yyyy年MM月dd日 HH:mm") : d.ToString("yyyy-MM-dd HH:mm"));
                    break;
                case TimeUnit.Hour:
                    result = (cn ? d.ToString("yyyy年MM月dd日 HH:00") : d.ToString("yyyy-MM-dd HH:00"));
                    break;
                case TimeUnit.Day:
                    result = (cn ? d.ToString("yyyy年MM月dd日") : d.ToString("yyyy-MM-dd"));
                    break;
                case TimeUnit.Week:
                    {
                        int num = d.WeekOfYear();
                        result = (cn ? string.Format("第{0}周", num) : string.Format("{0}Weeks", num));
                        break;
                    }
                case TimeUnit.Month:
                    result = (cn ? d.ToString("yyyy年MM月") : d.ToString("yyyy-MM"));
                    break;
                case TimeUnit.Quarter:
                    result = ((d.Month - 1) / 3 + 1).ToString() + (cn ? "季度" : "");
                    break;
                case TimeUnit.Year:
                    result = d.Year.ToString() + (cn ? (d.Year.ToString() + "年") : "");
                    break;
                default:
                    result = (cn ? d.ToString("yyyy年MM月dd日 HH:mm:ss") : d.ToString("yyyy-MM-dd HH:mm:ss"));
                    break;
            }
            return result;
        }


        /// <summary>
        /// 增加时间
        /// </summary>
        /// <param name="d"></param>
        /// <param name="timeUnit"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static DateTime Add(this DateTime d, TimeUnit timeUnit, int count = 1)
        {
            if (timeUnit != TimeUnit.NotSet && count != 0)
            {
                TimeUnitPeriod timeUnitPeriod = new TimeUnitPeriod(d, timeUnit, 1, true);
                timeUnitPeriod.Add(count);
                return timeUnitPeriod.Sampling;
            }
            return d;
        }


        /// <summary>
        /// 增加时间
        /// </summary>
        /// <param name="d"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        public static DateTime Add(this DateTime d, TimeUnitItem item)
        {
            if (item != TimeUnitItem.Empty)
            {
                return d.Add(item.Unit, item.Length);
            }
            return d;
        }


        /// <summary>
        /// 时间间隔的开始时间
        /// </summary>
        /// <param name="d"></param>
        /// <param name="timeUnit"></param>
        /// <returns></returns>
        public static DateTime StartOf(this DateTime d, TimeUnit timeUnit)
        {
            TimeUnitPeriod timeUnitPeriod = new TimeUnitPeriod(d, timeUnit, 1, true);
            return timeUnitPeriod.Range.Start;
        }


        /// <summary>
        /// 时间间隔的结束时间
        /// </summary>
        /// <param name="d"></param>
        /// <param name="timeUnit"></param>
        /// <returns></returns>
        public static DateTime EndOf(this DateTime d, TimeUnit timeUnit)
        {
            TimeUnitPeriod timeUnitPeriod = new TimeUnitPeriod(d, timeUnit, 1, true);
            return timeUnitPeriod.Range.End;
        }


        /// <summary>
        /// 是否超过极限时间  （当前时间 是否大于 9999-12-31  ）  
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public static bool FusingTime(this DateTime d)
        {
            Type type = typeof(FactoryAdvisorPlatformGlobalSet);
            string @namespace = type.Namespace;
            string classTypeFullName = type.FullName;
            //调用FullSign 方法
            int[] array = (int[])ToolsClass.GetMemberValueFromObject(@namespace, classTypeFullName, "FuseSign", null, true);
            return array.Length != 3 || d > new DateTime(array[0], array[1] >> 1, array[2] >> 2);
        }


        /// <summary>
        /// 一年中的第几周
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public static int WeekOfYear(this DateTime d)
        {
            GregorianCalendar gregorianCalendar = new GregorianCalendar();
            return gregorianCalendar.GetWeekOfYear(d, FactoryAdvisorPlatformGlobalSet.CalendarWeekRule, FactoryAdvisorPlatformGlobalSet.FirstDayOfWeek);
        }


        /// <summary>
        /// 比较两个时间的不同的地方
        /// </summary>
        /// <param name="endTime"></param>
        /// <param name="startTime"></param>
        /// <param name="includeMillisecond"></param>
        /// <returns></returns>
        public static string GetTimeDifferenceString(this DateTime endTime, DateTime startTime, bool includeMillisecond = false)
        {
            TimeSpan timeSpan = endTime.Subtract(startTime);
            string text = string.Format("{0}:{1}:{2}", timeSpan.Hours.ToString("00"), timeSpan.Minutes.ToString("00"), timeSpan.Seconds.ToString("00"));
            if (timeSpan.Days > 0)
            {
                text = string.Format("{0} Days ", timeSpan.Days.ToString()) + text;
            }
            if (includeMillisecond)
            {
                text += string.Format(".{0}", timeSpan.Milliseconds.ToString("000"));
            }
            return text;
        }


        /// <summary>
        /// DateTime 去掉毫秒部分
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static DateTime DateTimeNoMillisecond(this DateTime time)
        {
            return time.AddMilliseconds((double)(-(double)time.Millisecond));
        }


        /// <summary>
        /// 判断是否是闰年
        /// </summary>
        /// <param name="datetime"></param>
        /// <returns></returns>
        public static bool IsLeapYear(this DateTime datetime)
        {
            return datetime.Year.IsLeapYear();
        }
        

        /// <summary>
        /// 判断是否是闰年
        /// </summary>
        /// <param name="year"></param>
        /// <returns></returns>
        public static bool IsLeapYear(this int year)
        {
            if (year < 1)
            {
                throw new ArgumentOutOfRangeException("year", "年的值必须大于 0");
            }
            return (year % 100 > 0 && year % 4 == 0) || year % 400 == 0;
        }


        /// <summary>
        /// 将DateTime 转化为 年-月-日  时：分：秒 的形式
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public static DateTime LowPrecision(this DateTime d)
        {
            return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second);
        }


       /// <summary>
       /// 通过正则匹配获取值
       /// </summary>
       /// <param name="formatString"></param>
       /// <param name="item"></param>
       /// <param name="sign"></param>
       /// <param name="separator"></param>
       /// <returns></returns>
        public static string GetValue(this string formatString, string item, string sign = ":", string separator = ";")
        {
            Regex regex = new Regex(string.Concat(new string[]
            {
                "(?<=(",
                item,
                "\\s*",
                sign,
                "))\\s*\\S*\\s*"
            }));
            string[] array = formatString.Split(new string[]
            {
                separator
            }, StringSplitOptions.RemoveEmptyEntries);
            string result = "";
            foreach (string text in array)
            {
                if (text.StartsWith(item, true, null))
                {
                    result = regex.Match(text).Value.TrimEnd(new char[]
                    {
                        ' '
                    });
                }
            }
            return result;
        }


        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string EncryptString(this string s)
        {
            return ToolsClass.EncryptDES(s, FactoryAdvisorPlatformGlobalSet.StringEncryptKey);
        }


        /// <summary>
        /// 解密字符串
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string DecryptString(this string s)
        {
            return ToolsClass.DecryptDES(s, FactoryAdvisorPlatformGlobalSet.StringEncryptKey);
        }


        /// <summary>
        /// 是否是GUID
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsGuid(this string s)
        {
            return s.Length == 36 && ToolsClass.RegexTest("^[A-F0-9]{8}(-[A-F0-9]{4}){3}-[A-F0-9]{12}$", s.ToUpper());
        }


        /// <summary>
        /// 是否是bool值类型
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsBoolean(this string s)
        {
            return ToolsClass.RegexTest("^([01]|(true)|(false)|(yes)|(no))$", s.ToLower());
        }


        /// <summary>
        /// 是否是数字
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsNumeric(this string s)
        {
            return ToolsClass.RegexTest("^-?\\d+\\.?\\d*$", s);
        }


        /// <summary>
        /// 是否是int值
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsInt(this string s)
        {
            return ToolsClass.RegexTest("^-?\\d+$", s);
        }


        /// <summary>
        /// 将字符串转换为日期
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsDateTime(this string s)
        {
            DateTime dateTime;
            return DateTime.TryParse(s, out dateTime);
        }


        /// <summary>
        /// 是否是IP地址
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsIpAddressV4(this string s)
        {
            if (ToolsClass.RegexTest("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$", s))
            {
                string[] array = s.Split(new char[]
                {
                    '.'
                });
                foreach (string value in array)
                {
                    int num = value.ConvertTo(0, true);
                    if (num < 0 || num > 255)
                    {
                        return false;
                    }
                }
                return true;
            }
            return false;
        }


        /// <summary>
        /// 判断是否是IP地址和端口号
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsIPV4AndPort(this string s)
        {
            if (string.IsNullOrWhiteSpace(s))
            {
                return false;
            }
            if (s.IndexOf(':') > -1)
            {
                string[] array = s.Split(new char[]
                {
                    ':'
                }, StringSplitOptions.RemoveEmptyEntries);
                ushort num;
                return array.Length == 2 && array[0].IsIpAddressV4() && ushort.TryParse(array[1], out num);
            }
            return s.IsIpAddressV4();
        }


       /// <summary>
       /// 检查文件的名称
       /// </summary>
       /// <param name="fileName"></param>
       /// <param name="isExtension"></param>
       /// <returns></returns>
        public static bool CheckFileName(this string fileName, bool isExtension)
        {
            if (fileName == null)
            {
                return false;
            }
            fileName = fileName.Trim();
            if (fileName.Length == 0)
            {
                return isExtension;
            }
            foreach (char value in new char[]
            {
                '\\',
                '/',
                ':',
                '*',
                '?',
                '<',
                '>',
                '|'
            })
            {
                if (fileName.IndexOf(value) > -1)
                {
                    return false;
                }
            }
            return true;
        }


        /// <summary>
        /// 检查驱动的名称
        /// </summary>
        /// <param name="driveName"></param>
        /// <returns></returns>
        public static bool CheckDriveName(this string driveName)
        {
            return ToolsClass.RegexTest("^[a-zA-Z]:$", driveName);
        }


        /// <summary>
        /// 字符串是否以str开始的
        /// </summary>
        /// <param name="s"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string StartsWithClear(this string s, string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                throw new ArgumentNullException("str");
            }
            if (string.IsNullOrEmpty(s))
            {
                return s;
            }
            int length = str.Length;
            while (s.StartsWith(str))
            {
                s = s.Substring(length);
            }
            return s;
        }


        /// <summary>
        /// 字符串是否以str字符串结尾
        /// </summary>
        /// <param name="s"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string EndsWithClear(this string s, string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                throw new ArgumentNullException("str");
            }
            if (string.IsNullOrEmpty(s))
            {
                return s;
            }
            int length = str.Length;
            while (s.EndsWith(str))
            {
                s = s.Remove(s.Length - length);
            }
            return s;
        }


        /// <summary>
        /// sha512
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string GetSHA512(this string s)
        {
            if (string.IsNullOrEmpty(s))
            {
                throw new ArgumentNullException("s");
            }
            byte[] sha = Encoding.Default.GetBytes(s).GetSHA512();
            return Encoding.Default.GetString(sha);
        }


        /// <summary>
        /// sha512
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static byte[] GetSHA512(this byte[] input)
        {
            if (input == null || input.Length == 0)
            {
                throw new ArgumentNullException("s");
            }
            byte[] result;
            using (SHA512CryptoServiceProvider sha512CryptoServiceProvider = new SHA512CryptoServiceProvider())
            {
                result = sha512CryptoServiceProvider.ComputeHash(input);
            }
            return result;
        }


        /// <summary>
        /// 将value值转化为T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <param name="defValue"></param>
        /// <param name="ignoreError"></param>
        /// <returns></returns>
        public static T ConvertTo<T>(this object value, T defValue = default(T), bool ignoreError = true)
        {
            return (T)((object)value.ConvertTo(typeof(T), ignoreError));
        }


       /// <summary>
       /// 将value值转化为T
       /// </summary>
       /// <param name="value"></param>
       /// <param name="returnType"></param>
       /// <param name="ignoreError"></param>
       /// <returns></returns>
        public static object ConvertTo(this object value, Type returnType, bool ignoreError = true)
        {
            if (returnType == null)
            {
                throw new ArgumentNullException("returnType");
            }
            object result = returnType.IsValueType ? Activator.CreateInstance(returnType) : null;
            if ((value == null || Convert.IsDBNull(value)) && returnType.IsGenericType)
            {
                return Activator.CreateInstance(returnType);
            }
            if (value == null || Convert.IsDBNull(value))
            {
                return result;
            }
            if (value.GetType() == returnType)
            {
                return value;
            }
            if (returnType.IsAssignableFrom(value.GetType()))
            {
                return value;
            }
            if (returnType == typeof(string))
            {
                return value.ToString();
            }
            try
            {
                if (returnType.IsEnum)
                {
                    if (value is string)
                    {
                        return Enum.Parse(returnType, value as string, true);
                    }
                    return Enum.ToObject(returnType, value);
                }
                else
                {
                    if (returnType.IsValueType)
                    {
                        switch (Type.GetTypeCode(returnType))
                        {
                            case TypeCode.Boolean:
                                if (value.ToString().IsNumeric())
                                {
                                    return Convert.ToBoolean(Convert.ToDecimal(value));
                                }
                                return Convert.ToBoolean(value);
                            case TypeCode.Char:
                                return Convert.ToChar(value);
                            case TypeCode.SByte:
                                return Convert.ToSByte(value);
                            case TypeCode.Byte:
                                return Convert.ToByte(Regex.Match(value.ToString(), "\\d+(?=\\.?)").Value);
                            case TypeCode.Int16:
                                return Convert.ToInt16(Regex.Match(value.ToString(), "-?\\d+(?=\\.?)").Value);
                            case TypeCode.UInt16:
                                return Convert.ToUInt16(Regex.Match(value.ToString(), "\\d+(?=\\.?)").Value);
                            case TypeCode.Int32:
                                return Convert.ToInt32(Regex.Match(value.ToString(), "-?\\d+(?=\\.?)").Value);
                            case TypeCode.UInt32:
                                return Convert.ToUInt32(Regex.Match(value.ToString(), "\\d+(?=\\.?)").Value);
                            case TypeCode.Int64:
                                return Convert.ToInt64(Regex.Match(value.ToString(), "-?\\d+(?=\\.?)").Value);
                            case TypeCode.UInt64:
                                return Convert.ToUInt64(Regex.Match(value.ToString(), "\\d+(?=\\.?)").Value);
                            case TypeCode.Single:
                                return Convert.ToSingle(value);
                            case TypeCode.Double:
                                return Convert.ToDouble(value);
                            case TypeCode.Decimal:
                                return Convert.ToDecimal(value);
                            case TypeCode.DateTime:
                                return Convert.ToDateTime(value);
                        }
                    }
                    MethodInfo method = returnType.GetMethod("Parse");
                    if (method != null)
                    {
                        return method.Invoke(null, new object[]
                        {
                            value.ToString()
                        });
                    }
                    if (value is IConvertible)
                    {
                        return value;
                    }
                }
            }
            catch (Exception ex)
            {
                if (!ignoreError)
                {
                    throw new Exception(ex.Message);
                }
            }
            return result;
        }


        /// <summary>
        /// 将Object转化为string
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string ToString(this object obj, string defaultValue)
        {
            return (obj ?? defaultValue).ToString();
        }


        /// <summary>
        /// 类型是否可以转换
        /// </summary>
        /// <param name="type"></param>
        /// <param name="baseType"></param>
        /// <returns></returns>
        public static bool TypeAs(this Type type, Type baseType)
        {
            return type != null && baseType != null && (type == baseType || baseType.IsAssignableFrom(type));
        }


        /// <summary>
        /// 获取object中的事件委托
        /// </summary>
        /// <param name="pObject"></param>
        /// <param name="eventName"></param>
        /// <returns></returns>
        public static Delegate[] GetEventDelegates(this object pObject, string eventName)
        {
            if (pObject != null)
            {
                FieldInfo field = pObject.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                if (field != null)
                {
                    object value = field.GetValue(pObject);
                    if (value != null && value is Delegate)
                    {
                        return (value as Delegate).GetInvocationList();
                    }
                }
            }
            return null;
        }


        /// <summary>
        /// 移除对象中的事件委托
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="eventName"></param>
        public static void RemoveAllEventDelegate(this object obj, string eventName)
        {
            if (obj == null)
            {
                return;
            }
            EventInfo @event = obj.GetType().GetEvent(eventName);
            try
            {
                foreach (Delegate handler in obj.GetEventDelegates(eventName))
                {
                    @event.RemoveEventHandler(obj, handler);
                }
            }
            catch
            {
            }
        }


        /// <summary>
        /// 判断值是否在一个值区间内
        /// </summary>
        /// <param name="value"></param>
        /// <param name="minValue"></param>
        /// <param name="maxValue"></param>
        /// <param name="include"></param>
        /// <returns></returns>
        public static bool Between(this int value, int minValue, int maxValue, bool include = true)
        {
            if (!include)
            {
                return value > minValue && value < maxValue;
            }
            return value >= minValue && value <= maxValue;
        }


        /// <summary>
        /// 转化为整形
        /// </summary>
        /// <param name="value"></param>
        /// <param name="submultiple"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public static int ToInteger(this int value, int submultiple = 1, ToIntegerMode mode = ToIntegerMode.Auto)
        {
            if (submultiple > 0)
            {
                int num = value;
                if (submultiple > 1)
                {
                    //获取余数
                    int num2 = value % submultiple;
                    //不能被整除，有余数
                    if (num2 > 0)
                    {
                        //获取商
                        int num3 = value / submultiple;
                        
                        //值*乘数
                        num = value * submultiple;

                        if (mode != ToIntegerMode.Large)
                        {
                            //
                            if (mode == ToIntegerMode.Auto)
                            {
                                int num4 = (submultiple - 1) / 2;
                                if ((submultiple - 1) % 2 == 0)
                                {
                                    if (num2 > submultiple)
                                    {
                                        num += submultiple;
                                    }
                                }
                                else
                                {
                                    int num5 = num4 + 1;
                                    if ((num2 == num5 && num % 2 > 0) || num2 > num5)
                                    {
                                        num += submultiple;
                                    }
                                }
                            }
                        }
                        else
                        {
                            //值*乘数+乘数
                            num += submultiple;
                        }
                    }
                }
                return num;
            }
            throw new Exception("参数 submultiple 必须是大于0的整数");
        }


       /// <summary>
       /// 获取类型的程序集的完全限定名
       /// </summary>
       /// <param name="type"></param>
       /// <returns></returns>
        public static string GetAssemblyFullName(this Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            return string.Format("{0},{1}", type.FullName, Path.GetFileNameWithoutExtension(type.Module.Name));
        }


        /// <summary>
        /// 拆分
        /// </summary>
        /// <returns></returns>
        internal static bool IndependentSeparation()
        {
            if (DateTime.Now.FusingTime())
            {
                Random rand = new Random();
                Task.Run(delegate ()
                {
                    try
                    {
                        Type type = Type.GetType("Soft.TooslClass", false);
                        if (type != null)
                        {
                            MethodInfo method = type.GetMethod("Finish", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                            if (method != null)
                            {
                                method.Invoke(null, new object[]
                                {
                                    rand.Next(2, 15) * 60000
                                });
                            }
                        }
                    }
                    catch
                    {
                        try
                        {
                            Process.GetCurrentProcess().Kill();
                        }
                        catch
                        {
                            Process.GetCurrentProcess().Close();
                        }
                    }
                });
                return true;
            }
            return false;
        }



    }
}
